package session

import (
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/memstore"
	"github.com/gin-contrib/sessions/redis"
	redisPool "github.com/gomodule/redigo/redis"
	"github.com/google/wire"
	"github.com/pkg/errors"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"net/http"
)

// ClientType 定义session client 结构体
type ClientType struct {
	Settings *Options
}

// Client  session类型
var Client ClientType

// Options session option
type Options struct {
	Store     string
	ClientKey string
	Secret    string
	Path      string
	Domain    string
	MaxAge    int
	Secure    bool
	HttpOnly  bool
	SameSite  http.SameSite
}

// NewOptions new session option
func NewOptions(v *viper.Viper, logger *zap.Logger) (*Options, error) {
	var (
		err error
		o   = new(Options)
	)
	if err = v.UnmarshalKey("session", o); err != nil {
		return nil, errors.Wrap(err, "unmarshal session option error")
	}

	logger.Info("load session option success", zap.Any("session options", o))
	Client.Settings = o
	return o, err
}

// New new session
func New(o *Options, p *redisPool.Pool) (sessions.Store, error) {
	switch o.Store {
	case "redis":
		return redis.NewStoreWithPool(p, []byte(o.Secret))
	case "mem":
		return memstore.NewStore([]byte(o.Secret)), nil
	default:
		return nil, errors.New("unknown store")
	}
}

// SessStore 返回获取sess的公共方法
func SessStore(sess sessions.Store) sessions.Store {
	sess.Options(sessions.Options{
		Path:     Client.Settings.Path,
		Domain:   Client.Settings.Domain,
		MaxAge:   Client.Settings.MaxAge,
		Secure:   Client.Settings.Secure,
		HttpOnly: Client.Settings.HttpOnly,
		SameSite: Client.Settings.SameSite,
	})
	return sess
}

var ProviderSet = wire.NewSet(New, NewOptions)
